import pulpcore.Stage;
import pulpcore.sprite.ImageSprite;

/** Used to represent the players that the user controls to gain points. */
public class Player extends ImageSprite
{
	/** The different horizontal states of the player. */
	public static enum HorizontalState
	{
		/** The state that indicates the player is moving to the left. */
		MOVING_LEFT,
		/** The state that indicates the player is moving to the right. */
		MOVING_RIGHT,
		/** The state that indicates the player is not moving horizontally. */
		NOT_MOVING
	}
	/** The different vertical states of the player. */
	public static enum VerticalState
	{
		/** The state that indicates the player is currently on its way to jump on the seesaw. */
		FALLING,
		/** The state that indicates the player is currently on its way to land onto a branch. */
		FLYING,
		/** The state that indicates the player is currently jumping off of the branch and onto the seesaw. */
		JUMPING,
		/** The state that indicates the player is currently flying off of the seesaw and onto a branch. */
		LANDING,
		/** The state that indicates the player is currently on a branch. */
		ON_BRANCH,
		/** The state that indicates the player is currently on the seesaw. */
		ON_SEESAW
	}
	/** The limit that the player can move up. */
	private static final double ceiling;
	// TODO: We need to decide on the limit on vertical up movement.
	/** The proportion of the limit that the player can move up. */
	public static final double CEILING_PROPORTION = .05;
	// TODO: We need to decide on player height
	/** The height of the player. */
	private static final int HEIGHT = 50;
	// TODO: We need to decide on the limits of horizontal movement
	/** The proportion that the player can move horizontally in either direction. */
	private static final double HORIZONTAL_LIMIT_PROPORTION = .075;
	// TODO: We need to decide on player gravity
	/** The speed of the player while moving vertically. */
	private static final double PLAYER_GRAVITY = .15;
	// TODO: We need to decide on player speed
	/** The speed of the player while moving horizontally. */
	private static final double PLAYER_SPEED = .1;
	// TODO: We need to decide on player width
	/** The width of the player. */
	private static final int WIDTH = 50;
	/** The x anchor. */
	private static final double X_ANCHOR = .5;
	/** The y anchor. */
	private static final double Y_ANCHOR = 1.0;
	// * Calculates the ceiling based on the ceiling proportion and the player height. */
	static
	{
		ceiling = (CEILING_PROPORTION * Stage.getHeight()) + Player.HEIGHT;
	}

	/**
	 * Gets the player ceiling.
	 * 
	 * @return the player ceiling
	 */
	public static double getCeiling()
	{
		return ceiling;
	}
	/** The current horizontal state of the player. */
	private HorizontalState horizontalState;
	/** The limit that the player can move to the left. */
	private final double leftLimit;
	/** The limit that the player can move to the right. */
	private final double rightLimit;
	/** The current vertical state of the player. */
	private VerticalState verticalState;

	/**
	 * Instantiates a new player.
	 * 
	 * @param imageAsset
	 *            the file name of the image to be used as the player
	 * @param beginningState
	 *            the beginning state of the player
	 * @param xProportion
	 *            the proportion that the player should be at horizontally
	 * @param yProportion
	 *            the proportion that the player should be at vertically
	 */
	public Player(final String imageAsset, final VerticalState beginningState, final double xProportion, final double yProportion)
	{
		super(imageAsset, xProportion * Stage.getWidth(), yProportion * Stage.getHeight(), WIDTH, HEIGHT);
		setAnchor(X_ANCHOR, Y_ANCHOR);
		horizontalState = HorizontalState.NOT_MOVING;
		verticalState = beginningState;
		leftLimit = (xProportion - HORIZONTAL_LIMIT_PROPORTION) * Stage.getWidth();
		rightLimit = (xProportion + HORIZONTAL_LIMIT_PROPORTION) * Stage.getWidth();
	}

	/**
	 * Gets the current horizontal state.
	 * 
	 * @return the current horizontal state
	 */
	public HorizontalState getHorizontalState()
	{
		return horizontalState;
	}

	/**
	 * Gets the left horizontal limit.
	 * 
	 * @return the left horizontal limit
	 */
	public double getLeftHorizontalLimit()
	{
		return leftLimit;
	}

	/**
	 * Gets the right horizontal limit.
	 * 
	 * @return the right horizontal limit
	 */
	public double getRightHorizontalLimit()
	{
		return rightLimit;
	}

	/**
	 * Gets the current vertical state.
	 * 
	 * @return the current vertical state
	 */
	public VerticalState getVerticalState()
	{
		return verticalState;
	}

	/**
	 * Moves the player horizontally based on current horizontal state.
	 * 
	 * @param elapsedTime
	 *            the elapsed time
	 */
	public void MoveHorizontally(final int elapsedTime)
	{
		int direction;
		switch (horizontalState)
		{
		default:
		case NOT_MOVING:
			return;
		case MOVING_LEFT:
			direction = -1;
			break;
		case MOVING_RIGHT:
			direction = 1;
		}
		x.set(x.get() + (PLAYER_SPEED * direction * elapsedTime));
	}

	/**
	 * Moves the player vertically based on current vertical state.
	 * 
	 * @param elapsedTime
	 *            the elapsed time
	 */
	public void MoveVertically(final int elapsedTime)
	{
		int direction;
		switch (verticalState)
		{
		default:
		case ON_BRANCH:
		case ON_SEESAW:
			return;
		case JUMPING:
		case FLYING:
			direction = -1;
			break;
		case LANDING:
		case FALLING:
			direction = 1;
		}
		y.set(y.get() + (PLAYER_GRAVITY * direction * elapsedTime));
	}

	/**
	 * Sets the new horizontal state.
	 * 
	 * @param newHorizontalState
	 *            the new horizontal state
	 */
	public void setHorizontalState(final HorizontalState newHorizontalState)
	{
		horizontalState = newHorizontalState;
	}

	/**
	 * Sets the new vertical state.
	 * 
	 * @param newVerticalState
	 *            the new vertical state
	 */
	public void setVerticalState(final VerticalState newVerticalState)
	{
		verticalState = newVerticalState;
	}
}